package com.dc.config.shiro;


import com.dc.common.constant.CustomConstants;
import com.dc.common.core.LoginBody;
import com.dc.common.core.LoginRole;
import com.dc.common.core.LoginUser;
import com.dc.common.core.MyToken;
import com.dc.common.utils.BeanUtil;
import com.dc.common.utils.RsaUtil;
import com.dc.common.utils.ShiroUtil;
import com.dc.project.system.entity.SysPost;
import com.dc.project.system.entity.SysRole;
import com.dc.project.system.entity.SysUser;
import com.dc.project.system.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhuangcy
 * @date 2021/1/18
 * @description 系统用户认证授权
 */
@Slf4j
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private SysUserService sysUserService;

    /**
     * 认证
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.info("---------------- 执行 Shiro 认证 ---------------------");
        MyToken myToken = (MyToken) authenticationToken;
        LoginBody loginBody = myToken.getLoginBody();
        SysUser one = sysUserService.getUserByAccount(loginBody.getUsername());
        if (one == null) {
            throw new UnknownAccountException();
        } else if (!CustomConstants.ENABLED_STATE.equals(one.getStatus())) {
            throw new ExpiredCredentialsException();
        } else if (!RsaUtil.decrypt(one.getPassword()).equals(loginBody.getPassword())) {
            throw new IncorrectCredentialsException();
        }
        LoginUser loginUser = new LoginUser();
        BeanUtil.copyBeanProp(loginUser, one);
        String newToken = myToken.getToken();
        loginUser.setToken(newToken);
        //查询权限
        Set<String> roles = new HashSet<>();
        Set<String> permissions = new HashSet<>();
        List<SysPost> userPosts = new ArrayList<>();
        if (Arrays.asList(CustomConstants.SUPER_ADMIN).contains(loginBody.getUsername())) {
            roles.add("*");
            permissions.add("*");
            userPosts = sysUserService.getUserPosts(null);
        } else {
            List<SysRole> roleList = sysUserService.getUserRoleByUserId(one.getUserId());
            roles = roleList.stream().map(SysRole::getRoleCode).collect(Collectors.toSet());
            Set<Integer> ids = roleList.stream().map(SysRole::getRoleId).collect(Collectors.toSet());
            permissions = sysUserService.getMenuIdByRoleIds(ids);
            List<LoginRole> loginRoles = roleList.stream().map(item -> {
                LoginRole role = new LoginRole();
                role.setRoleId(item.getRoleId());
                role.setRoleName(item.getRoleName());
                role.setRoleCode(item.getRoleCode());
                role.setDataScope(item.getDataScope());
                return role;
            }).collect(Collectors.toList());
            loginUser.setLoginRoles(loginRoles);
            userPosts = sysUserService.getUserPosts(one.getUserId());
        }
        if (!userPosts.isEmpty()) {
            List<String> posts = userPosts.stream().map(item -> item.getPostCode()).collect(Collectors.toList());
            loginUser.setPosts(posts);
        }
        loginUser.setRoles(roles);
        loginUser.setPermissions(permissions);
        return new SimpleAuthenticationInfo(loginUser, newToken, getName());
    }

    /**
     * 授权
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("---------------- 执行 Shiro 授权 ---------------------");
        LoginUser userInfo = ShiroUtil.getUserInfo();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(userInfo.getRoles());
        authorizationInfo.addStringPermissions(userInfo.getPermissions());
        return authorizationInfo;
    }

}
